package com.yhsimon.realm.member.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yhsimon.realm.member.constant.ResultCodeEnum;
import com.yhsimon.realm.member.entity.article.ArticleEntity;
import com.yhsimon.realm.member.entity.user.UserEntity;
import com.yhsimon.realm.member.mapper.UserMapper;
import com.yhsimon.realm.member.service.ArticleService;
import com.yhsimon.realm.member.mapper.ArticleMapper;
import com.yhsimon.realm.member.utils.R;
import com.yhsimon.realm.member.vo.article.ArticleVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;


/**
 * @author 19819
 * @description 针对表【ums_article(文章信息表)】的数据库操作Service实现
 * @createDate 2024-04-27 20:55:28
 */
@Service
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, ArticleEntity>
        implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public List<ArticleVo> listArticleByUserId(Long userId) {
        QueryWrapper<ArticleEntity> queryWrapper = new QueryWrapper<ArticleEntity>().eq("user_id", userId).eq("status", 0).eq("is_deleted", 0);
        List<ArticleEntity> articleList = this.list(queryWrapper);
        return articleEntityToVo(articleList);
    }

    @Override
    @SentinelResource(value = "listArticleById", blockHandler = "blockExceptionHandler")
    public R listArticleById(Long id, String userId) {
        ArticleVo articleVo = new ArticleVo();
        QueryWrapper<ArticleEntity> eq = new QueryWrapper<ArticleEntity>().eq("id", id).eq("is_deleted", 0);
        List<ArticleEntity> articleEntityList = this.list(eq);
        if (articleEntityList == null || articleEntityList.size() < 1) {
            log.error("文章id无效，请核验该文章");
            return R.error("文章id无效，请核验该文章");
        }
        ArticleEntity articleEntity = articleEntityList.get(0);
        // 如果是已发表的文章，先更新阅读数
        if (articleEntity.getStatus() == 0) {
            articleEntity.setViewCount(articleEntity.getViewCount() + 1);
            this.updateById(articleEntity);
        }

        UserEntity userEntity = userMapper.selectById(articleEntity.getUserId());

        BeanUtils.copyProperties(articleEntity, articleVo);
        articleVo.setNickname(userEntity.getNickname());

        // 从redis中获取点赞数
        String key = "article:like:" + id;
        SetOperations<String, String> setOperations = redisTemplate.opsForSet();
        Long likeCount = setOperations.size(key);
        articleVo.setLikeCount(likeCount == null ? 0 : likeCount.intValue());
        // 判断当前用户是否点赞过该文章
        articleVo.setLikeArticle(isLikeArticle(articleEntity.getId().toString(), userId));
        return R.ok().put("data", articleVo);
    }

    public R blockExceptionHandler(Long id, String userId, BlockException e) {
        if (e instanceof FlowException) {
            return R.error(ResultCodeEnum.SYSTEM_BUSY);
        } else if (e instanceof ParamFlowException) {
            return R.error(ResultCodeEnum.HOT_SPOT_PARAMETER_CURRENT_LIMITING);
        } else if (e instanceof DegradeException) {
            return R.error(ResultCodeEnum.REQUEST_DOWNGRADE);
        } else if (e instanceof AuthorityException) {
            return R.error(ResultCodeEnum.NO_PERMISSION_TO_ACCESS);
        }
        return R.error();
    }

    @Override
    public boolean existsArticle(Long id) {
        QueryWrapper<ArticleEntity> eq = new QueryWrapper<ArticleEntity>().eq("id", id).eq("is_deleted", 0);
        return this.exists(eq);
    }

    /**
     * TODO 线程池未必有效 配置问题？
     */
    @Override
    public List<ArticleVo> listArticleAll() {
        List<ArticleEntity> articleEntityList = articleMapper.selectList(new QueryWrapper<ArticleEntity>().eq("is_deleted", 0).eq("status", 0));
        return articleEntityToVo(articleEntityList);
    }

    @Override
    public void likeArticle(String id, String userId) {
        // 假设articleId是"1"
        String key = "article:like:" + id;
        SetOperations<String, String> setOperations = redisTemplate.opsForSet();
        if (Boolean.FALSE.equals(setOperations.isMember(key, userId))) {
            setOperations.add(key, userId);
        } else {
            setOperations.remove(key, userId);
        }
    }

    @Override
    public List<ArticleVo> listArticleDraftByUserId(Long userId) {
        QueryWrapper<ArticleEntity> queryWrapper = new QueryWrapper<ArticleEntity>().eq("user_id", userId).eq("status", 1);
        List<ArticleEntity> articleList = this.list(queryWrapper);
        return articleEntityToVo(articleList);
    }

    public boolean isLikeArticle(String id, String userId) {
        String key = "article:like:" + id;
        SetOperations<String, String> setOperations = redisTemplate.opsForSet();
        return Boolean.TRUE.equals(setOperations.isMember(key, userId));
    }

    private List<ArticleVo> articleEntityToVo(List<ArticleEntity> articleEntityList) {
        List<ArticleVo> articleVoList = new ArrayList<>();
        for (ArticleEntity articleEntity : articleEntityList) {
            try {
                UserEntity userEntity = userMapper.selectById(articleEntity.getUserId());
                ArticleVo articleVo = new ArticleVo();
                BeanUtils.copyProperties(articleEntity, articleVo);
                articleVo.setNickname(userEntity.getNickname());
                // 从redis中获取点赞数
                String key = "article:like:" + articleEntity.getId();
                SetOperations<String, String> setOperations = redisTemplate.opsForSet();
                Long likeCount = setOperations.size(key);
                articleVo.setLikeCount(likeCount == null ? 0 : likeCount.intValue());
                articleVoList.add(articleVo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return articleVoList;
    }
}




